﻿using System;
using System.Collections.Generic;
using System.Linq;
using Api.Model;
using Core.ProxyService;
using CThru.Silverlight;
using NUnit.Framework;
using TypeMock.ArrangeActAssert;

namespace CompositeProxyService.Test.Unit
{
    [TestFixture]
    public class CompositeProxyServiceTests
    {
        private CompositeProxyService compositeProxyService;
        private ICoreProxyService firstService;
        private ICoreProxyService secondService;

        [SetUp]
        public void Setup()
        {
            firstService = Isolate.Fake.Instance<ICoreProxyService>();
            secondService = Isolate.Fake.Instance<ICoreProxyService>();

            compositeProxyService = new CompositeProxyService(firstService, secondService);
        }

        [Test, SilverlightUnitTest]
        public void GetArticlesAsync_2ServicesInjectedCallbackNotNull_GetArticlesAsyncCalledOnServices()
        {
            compositeProxyService.GetArticlesAsync(args => { });

            Isolate.Verify.WasCalledWithAnyArguments(() => firstService.GetArticlesAsync(null));
            Isolate.Verify.WasCalledWithAnyArguments(() => secondService.GetArticlesAsync(null));
        }

        [Test, SilverlightUnitTest]
        public void GetArticlesAsync_FirstService3ArticlesSecondService2Articles_ServiceReturns5Articles()
        {
            MakeServiceReturnsArticles(firstService, 3);
            MakeServiceReturnsArticles(secondService, 2);
            int articlesCount = 0;

            compositeProxyService.GetArticlesAsync(args => { articlesCount = args.Result.Count(); });

            Assert.AreEqual(5, articlesCount);
        }

        [Test, SilverlightUnitTest]
        public void GetArticlesAsync_FirstServiceFails_ServiceReturns2Articles()
        {
            MakeServiceFailing(firstService);
            MakeServiceReturnsArticles(secondService, 2);
            int articlesCount = 0;

            compositeProxyService.GetArticlesAsync(args => { articlesCount = args.Result.Count(); });

            Assert.AreEqual(2, articlesCount);
        }

        [Test, SilverlightUnitTest]
        public void GetArticlesAsync_SecondServiceFails_ServiceReturns3Articles()
        {
            MakeServiceReturnsArticles(firstService, 3);
            MakeServiceFailing(secondService);
            int articlesCount = 0;

            compositeProxyService.GetArticlesAsync(args => { articlesCount = args.Result.Count(); });

            Assert.AreEqual(3, articlesCount);
        }

        [Test, SilverlightUnitTest]
        public void GetArticlesAsync_BothServiceFails_ServiceReturnsError()
        {
            MakeServiceFailing(firstService);
            MakeServiceFailing(secondService);
            Exception error = null;

            compositeProxyService.GetArticlesAsync(args => { error = args.Error; });

            Assert.NotNull(error);
        }

        public void MakeServiceReturnsArticles(ICoreProxyService mockService, int articlesCount)
        {
            Isolate.WhenCalled(() => mockService.GetArticlesAsync(fakeArgs => { })).DoInstead(context =>
                {
                    var lamda = context.Parameters[0] as Action<ArticlesDownloadedEventArgs>;
                    var articles = new List<Article>();

                    for (int i = 0; i < articlesCount; i++)
                    {
                        articles.Add(new Article());
                    }

                    var args = new ArticlesDownloadedEventArgs(null, false, null, articles);
                    lamda(args);
                });
        }

        public void MakeServiceFailing(ICoreProxyService mockService)
        {
            Isolate.WhenCalled(() => mockService.GetArticlesAsync(fakeArgs => { })).DoInstead(context =>
                {
                    var lamda =  context.Parameters[0] as Action<ArticlesDownloadedEventArgs>;
                    var args = new ArticlesDownloadedEventArgs(new Exception(), true, null, null);
                    lamda(args);
                });
        }
    }
}
